#pragma once
class CTangoSocketServer : public JetByteTools::Win32::CSocketServer
{
public:

	CTangoSocketServer(
		const JetByteTools::Win32::ICriticalSectionFactory &lockFactory,
		JetByteTools::Win32::CSocketServer::IOPool &ioPool,
		unsigned long addressToListenOn,
		unsigned short portToListenOn,
		size_t maxFreeSockets,
		size_t maxFreeBuffers,
		size_t bufferSize,
		size_t numberOfUserDataSlots,
		CTangoThreadPool &businessLogicPool,
		size_t maxMessageSize,
		bool usingReadSequenceNumbers,
		bool usingSequenceNumbers,
		bool issueReadLate);

public:
	void RePostCmd(Socket *pSocket,
		JetByteTools::Win32::CIOBuffer *pBuffer);

private:

	virtual void OnStartAcceptingConnections();
	virtual void OnStopAcceptingConnections();
	virtual void OnShutdownInitiated();
	virtual void OnShutdownComplete();

	virtual void OnConnectionCreated();
	virtual void OnConnectionEstablished(
		Socket *pSocket,
		JetByteTools::Win32::CIOBuffer *pAddress);
	virtual void OnConnectionClientClose(
		Socket *pSocket);
	virtual void OnConnectionReset(
		Socket *pSocket);
	virtual bool OnConnectionClosing(
		Socket *pSocket);
	virtual void OnConnectionClosed(
		Socket *pSocket);
	virtual void OnConnectionDestroyed();
	virtual void OnSocketReleased(
		Socket *pSocket);

	virtual void OnConnectionError(
		ConnectionErrorSource source,
		Socket *pSocket,
		JetByteTools::Win32::CIOBuffer *pBuffer,
		DWORD lastError);

	virtual void OnError(
		const JetByteTools::Win32::_tstring &message);

	virtual void OnBufferCreated();
	virtual void OnBufferAllocated();
	virtual void OnBufferReleased();
	virtual void OnBufferDestroyed();

	virtual void ReadCompleted(
		Socket *pSocket,
		JetByteTools::Win32::CIOBuffer *pBuffer);

	size_t GetMinimumMessageSize() const;

	size_t GetMessageSize(
		const JetByteTools::Win32::CIOBuffer *pBuffer) const;

	void ProcessDataStream(
		Socket *pSocket,
		const JetByteTools::Win32::CIOBuffer *pBuffer);

	void ProcessCommand(
		Socket *pSocket,
		JetByteTools::Win32::CIOBuffer *pBuffer);

	CTangoThreadPool &m_pool;

	JetByteTools::Win32::CIOBuffer::Allocator m_allocator;

	//lint -e{1516} Data member hides inherited data member from Alocator
	JetByteTools::Win32::CCriticalSection m_criticalSection;

	class CPerConnectionData
	{
	public:

		CPerConnectionData(
			JetByteTools::Win32::CCriticalSection &m_criticalSection,
			JetByteTools::Win32::CIOBuffer::Allocator &m_allocator);

		~CPerConnectionData();

		bool HasBuffer() const;

		void NewBuffer();

		void AddData(
			const BYTE *pData,
			size_t dataLength);

		JetByteTools::Win32::CIOBuffer *RemoveTransferBuffer();

		bool Finished();

		void Finished(
			bool finished);

		size_t m_messageSize;
		JetByteTools::Win32::CIOBuffer *m_pTransferBuffer;
		JetByteTools::Win32::CIOBuffer::InOrderBufferList m_outOfSequenceReads;

	private:

		long m_transferSequenceNumber;

		long m_finished;

		JetByteTools::Win32::CIOBuffer::Allocator &m_allocator;

		// No copies, do not implement
		CPerConnectionData(const CPerConnectionData &rhs);
		CPerConnectionData &operator=(const CPerConnectionData &rhs);
	};

	void SetPerConnectionData(
		Socket *pSocket,
		CPerConnectionData *pData);

	CPerConnectionData *GetPerConnectionData(
		const Socket *pSocket);

	const size_t m_maxMessageSize;

	const bool m_usingSequenceNumbers;

	const bool m_issueEarlyRead;

	const size_t m_userDataIndex;

	// No copies do not implement
	CTangoSocketServer(const CTangoSocketServer &rhs);
	CTangoSocketServer &operator=(const CTangoSocketServer &rhs);
};

